%   Initialization
clear; close all; clc;

%   ========    Part1: Ploting Data Sets    ========
%   Load the data
data = load('data1.txt');
%   Initialize the variables of the data
X = data(:, 1:2);
y = data(:, 3);
fprintf('Plotting the data with + indicating (y = 1) examples and o indicating (y = 0) examples.\n');
%   Plot the data
plotData(X, y);
%   Set the x−axis label
xlabel('Exam 1 score');
%   Set the y−axis label
ylabel('Exam 2 score');
%   Add the legend to the plot
legend('Admitted', 'Not admitted');
%   Pause the program
fprintf('Program paused. Press any key to continue.\n'); pause;

%   ========    Part 2: Gradient Descent    ========
%   Get the size of the X
[m, n] = size(X);
%   Add a column of ones to the X
X = [ones(m, 1), X];
%   Initialize the fitting parameters
initial_theta = zeros(n + 1, 1);
%   Compute the initial cost and gradient
[cost, grad] = costFunction(initial_theta, X, y);
fprintf('Cost at initial theta (zeros): %f\n', cost);
fprintf('Gradient at initial theta (zeros): \n');
fprintf(' %f \n', grad);
%   Pause the program
fprintf('Program paused. Press any key to continue.\n'); pause;

%   ========    Part 3: Optimizing With The fminunc    ========
%   Set the options for fminunc
%   Options: GradObj --- open/close the gradient for the objective function defined by user
%   Options: MaxIter --- the max iterations of the compute
options = optimset('GradObj', 'on', 'MaxIter', 400);
%   Run the fminunc function to train the theta
[theta, cost] = fminunc(@(t)(costFunction(t, X, y)), initial_theta, options);
fprintf('Cost at theta found by fminunc: %f\n', cost);
fprintf('theta: \n');
fprintf(' %f \n', theta);
%   Plot the decision boundary
plotDecisionBoundary(theta, X, y);
%   Set the x−axis label
xlabel('Exam 1 score');
%   Set the y−axis label
ylabel('Exam 2 score');
%   Add the legend to the plot
legend('Admitted', 'Not admitted', 'Decision Boundary');
%   Pause the program
fprintf('Program paused. Press any key to continue.\n'); pause;

%   ========    Part 4: Prediction And Accuracy    ========
%   Compute the probability with the data
prob = sigmoid([1, 45, 85] * theta);
fprintf('For a student with scores 45 and 85, we predict an admission probability of %f\n', prob);
%   Compute the accuracy on our training set
p = predict(theta, X);
fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100);
